package com.syh.jn.scm.domain.supplier.entity.finance;

import cn.redscarf.commons.util.bean.ExtBeanUtils;
import cn.redscarf.commons.util.other.ExtAssert;
import cn.redscarf.commons.spring.SpringContextUtils;
import cn.redscarf.commons.util.validator.ValidationUtils;
import cn.redscarf.commons.wrapper.Restrictions;
import cn.redscarf.commons.wrapper.Wrapper;
import com.syh.core.ddd.domain.AbstractSimpleAggregate;
import com.syh.core.ddd.domain.CodeExpEnum;
import com.syh.core.ddd.domain.CodeGenerateUtil;
import com.syh.jn.scm.domain.supplier.repository.finance.PaymentBillReadRepository;
import com.syh.jn.scm.domain.supplier.repository.finance.ReceiptBillReadRepository;
import com.syh.jn.scm.domain.supplier.repository.finance.StatementAccountBillReadRepository;
import com.syh.jn.scm.dto.supplier.finance.statementAccountBill.StatementAccountBillMto;
import com.syh.jn.scm.dto.supplier.finance.statementAccountBill.StatementAccountBillSto;
import com.syh.jn.scm.dto.support.FilesDto;
import com.syh.jn.scm.exception.BusinessException;
import com.syh.jn.scm.service.api.supplier.finance.enums.StatementAccountBillEnum;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 对账单
 */
@Data
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
public class StatementAccountBill extends AbstractSimpleAggregate<Long> {
  /**
   * 生成对账单
   *
   * @param sto
   * @return
   */
  public StatementAccountBill(StatementAccountBillSto sto) {
    ExtAssert.notNull(sto, "对象为空");
    ValidationUtils.validate(sto);

    ExtBeanUtils.copyProperties(sto, this);
    this.createTimeStamp = System.currentTimeMillis();
    this.inputTimestamp = System.currentTimeMillis();
    this.price = BigDecimal.ZERO;
    //新建时默认到账金额为0
    this.makeCollectionsPrice = BigDecimal.ZERO;
    //新建时默认已生成到账金额为0
    this.generatedCollectionsPrice = BigDecimal.ZERO;
    //新建时默认开票金额为0
    this.ticketPrice = BigDecimal.ZERO;
    //新建时默认已生成开票金额为0
    this.generatedTicketPrice = BigDecimal.ZERO;
    this.businessState = StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus();
    this.financeState = StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus();
    this.ticketState = StatementAccountBillEnum.NOT_INVOICE.getStatus();
    //新建时候未付款
    this.state = StatementAccountBillEnum.MONEY_UNRECEIVED.getStatus();
    this.setUuid(UUID.randomUUID().toString());
    this.setCode(CodeGenerateUtil.codeGenerate(CodeExpEnum.STATEMENT_ACCOUNT_BILL_EXP.getCodeExp(), sto.getCustomerId()));

    this.statementAccountBillItems = new ArrayList<>();
    sto.getItems().forEach(item -> {
      StatementAccountBillItem billItem = new StatementAccountBillItem(item, sto.getCustomerType(), sto.getCustomerId());
      this.statementAccountBillItems.add(billItem);
    });
    this.priceCount();
  }

  public void modify(StatementAccountBillMto mto) {
    ExtAssert.notNull(mto, "对象为空");
    ValidationUtils.validate(mto);
    StatementAccountBillReadRepository statementAccountBillReadRepository = (StatementAccountBillReadRepository) SpringContextUtils.getBean(StatementAccountBillReadRepository.class);
    StatementAccountBill statementAccountBill = statementAccountBillReadRepository.getById(mto.getId());
    if ( statementAccountBill == null ) {
      throw new IllegalMonitorStateException("找不到该订单");
    }
    if ( !statementAccountBill.getBusinessState().equals(StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus())
            || !statementAccountBill.getFinanceState().equals(StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus()))  {
      throw new IllegalMonitorStateException("业务或财务已有一方确认");
    }
    this.lastUpdateTimeStamp = System.currentTimeMillis();

    ExtBeanUtils.copyProperties(mto, this, false);
    this.price = BigDecimal.ZERO;
    this.statementAccountBillItems = new ArrayList<>();
    mto.getItems().forEach(item -> {
      StatementAccountBillItem billItem = new StatementAccountBillItem(item, mto.getCustomerType(), mto.getCustomerId());
      this.statementAccountBillItems.add(billItem);
    });
    this.priceCount();
  }

  /**
   * 计算对账金额
   */
  private void priceCount(){
    this.statementAccountBillItems.forEach(billItem -> {
      if (StatementAccountBillEnum.CUSTOMER_TYPE_UPSTREAM.getStatus().equals(this.customerType)) {
        // 为了直观这里不用枚举
        switch (billItem.getSourceType()) {
          // 采购单
          case 2:
            this.price = this.price.add(billItem.getTotalAmount());
            break;
          // 采购退货
          case 3:
            this.price = this.price.subtract(billItem.getTotalAmount());
            break;
          // 费用单
          case 4:
            this.price = this.price.add(billItem.getTotalAmount());
            break;
          // 收入单
          case 5:
            this.price = this.price.subtract(billItem.getTotalAmount());
            break;
        }
      }

      if (StatementAccountBillEnum.CUSTOMER_TYPE_DOWNSTREAM.getStatus().equals(this.customerType)) {
        // 为了直观这里不用枚举
        switch (billItem.getSourceType()) {
          // 销售单
          case 0:
            this.price = this.price.add(billItem.getTotalAmount());
            break;
          // 销售退货
          case 1:
            this.price = this.price.subtract(billItem.getTotalAmount());
            break;
          // 费用单
          case 4:
            this.price = this.price.subtract(billItem.getTotalAmount());
            break;
          // 收入单
          case 5:
            this.price = this.price.add(billItem.getTotalAmount());
            break;
        }
      }
      if (StatementAccountBillEnum.CUSTOMER_TYPE_LOGISTICS.getStatus().equals(this.customerType)) {
        // 为了直观这里不用枚举
        switch (billItem.getSourceType()) {
          // 费用单
          case 4:
            this.price = this.price.add(billItem.getTotalAmount());
            break;
          // 收入单
          case 5:
            this.price = this.price.subtract(billItem.getTotalAmount());
            break;
          // 物流单
          case 6:
            this.price = this.price.add(billItem.getTotalAmount());
            break;
        }
      }
    });
  }

  /**
   * 设置已生成收付款单金额
   */
  public void addGeneratedCollectionsPrice(BigDecimal money) {
    this.generatedCollectionsPrice = this.generatedCollectionsPrice.add(money);
    if (this.generatedCollectionsPrice.doubleValue() > this.price.doubleValue()) {
      throw new BusinessException("生成金额大于对账单收款金额");
    }
  }

  /**
   * 设置取消已生成收付款单金额
   */
  public void subGeneratedCollectionsPrice(BigDecimal money) {
    this.generatedCollectionsPrice = this.generatedCollectionsPrice.subtract(money);
    if (this.generatedCollectionsPrice.doubleValue() < 0 ) {
      throw new BusinessException("应减少的已生成收付款金额异常，小于0");
    }
  }

  /**
   * 设置到账金额
   */
  public void addMakeCollectionsPrice(BigDecimal money) {
    this.makeCollectionsPrice = this.makeCollectionsPrice.add(money);
    if (this.makeCollectionsPrice.doubleValue() > this.price.doubleValue()) {
      throw new BusinessException("到账金额大于对账单收款金额");
    }
    if (this.makeCollectionsPrice.doubleValue() < this.price.doubleValue()) {
      this.state = StatementAccountBillEnum.PART_MONEY_RECEIVED.getStatus();
    }
    if (this.makeCollectionsPrice.doubleValue() == this.price.doubleValue()) {
      this.state = StatementAccountBillEnum.MONEY_RECEIVED.getStatus();
    }
  }

  /**
   * 设置取消到账金额和收款状态
   */
  public void subMakeCollectionsPrice(BigDecimal money) {
    this.makeCollectionsPrice = this.makeCollectionsPrice.subtract(money);
    if (this.makeCollectionsPrice.doubleValue() == 0) {
      this.state = StatementAccountBillEnum.MONEY_UNRECEIVED.getStatus();
    }
    if (this.makeCollectionsPrice.doubleValue() != 0 && this.makeCollectionsPrice.doubleValue() < this.price.doubleValue()) {
      this.state = StatementAccountBillEnum.PART_MONEY_RECEIVED.getStatus();
    }
  }

  /**
   * 增加已生成开票金额,以及更改开票状态
   */
  public void addGeneratedTicketPrice(BigDecimal money) {
    this.generatedTicketPrice = this.generatedTicketPrice.add(money);
    if (this.generatedTicketPrice.doubleValue() > this.price.doubleValue()) {
      throw new BusinessException("已生成开票金额大于对账单金额");
    }
  }

  /**
   * 减少已生成开票金额,以及更改开票状态
   */
  public void subGeneratedTicketPrice(BigDecimal money) {
    this.generatedTicketPrice = this.generatedTicketPrice.subtract(money);
    if (this.generatedTicketPrice.doubleValue() < 0 ) {
      throw new BusinessException("应减少的已生成开票金额异常，小于0");
    }
  }

  /**
   * 增加开票金额,以及更改开票状态
   */
  public void addTicketPrice(BigDecimal money) {
    this.ticketPrice = this.ticketPrice.add(money);

    if (this.ticketPrice.doubleValue() > this.price.doubleValue()) {
      throw new BusinessException("开票金额大于对账单金额");
    }
    if (this.ticketPrice.doubleValue() < this.price.doubleValue()) {
      this.ticketState = StatementAccountBillEnum.PART_INVOICED.getStatus();
    }
    if (this.ticketPrice.doubleValue() == this.price.doubleValue()) {
      this.ticketState = StatementAccountBillEnum.FINISH_INVOICED.getStatus();
    }
  }

  /**
   * 减少开票金额,以及开票状态
   */
  public void subTicketPrice(BigDecimal money) {
    this.ticketPrice = this.ticketPrice.subtract(money);

    if (this.ticketPrice.doubleValue() < 0) {
      throw new BusinessException("应减少的开票金额异常，小于0");
    }
    if (this.ticketPrice.doubleValue() < this.price.doubleValue()) {
      this.ticketState = StatementAccountBillEnum.PART_INVOICED.getStatus();
    }
    if (this.ticketPrice.doubleValue() == 0) {
      this.ticketState = StatementAccountBillEnum.NOT_INVOICE.getStatus();
    }
  }

  /**
   * 数据销毁
   */
  public void destroy() {
    if (!StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus().equals(this.businessState)
            || !StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus().equals(this.financeState)
            || !StatementAccountBillEnum.NOT_INVOICE.getStatus().equals(this.ticketState)) {
      throw new BusinessException("订单处于确认状态,删除失败!");
    }
    //查看付款是否存在对账信息
    PaymentBillReadRepository paymentBillReadRepository = (PaymentBillReadRepository) SpringContextUtils.getBean(PaymentBillReadRepository.class);
    Wrapper paymentBillWrapper = Wrapper.build();
    paymentBillWrapper.append(Restrictions.eq("statementOfAccountId", this.id));
    Integer paymentCount = paymentBillReadRepository.getCount(paymentBillWrapper);
    if (paymentCount > 0) {
      throw new BusinessException("该数据在付款单存在记录,删除失败!");
    }
    //查看收款是否存在对账信息
    ReceiptBillReadRepository receiptBillReadRepository = (ReceiptBillReadRepository) SpringContextUtils.getBean(ReceiptBillReadRepository.class);
    Wrapper receiptBillWrapper = Wrapper.build();
    receiptBillWrapper.append(Restrictions.eq("statementOfAccountId", this.id));
    Integer receiptCount = receiptBillReadRepository.getCount(receiptBillWrapper);
    if (receiptCount > 0) {
      throw new BusinessException("该数据在收款单存在记录,删除失败!");
    }

  }

  /**
   * 业务确认
   */
  public void businessConfirmation() {
    //物流对账单区别对待
    if (this.customerType.equals(StatementAccountBillEnum.CUSTOMER_TYPE_LOGISTICS.getStatus())) {
      if (StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus().equals(this.businessState)) {
        this.businessState = StatementAccountBillEnum.BOTH_CONFIRM.getStatus();
      }
    } else {//上下游对账单
      if (StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus().equals(this.businessState)) {
        this.businessState = StatementAccountBillEnum.OUR_CONFIRM.getStatus();
      } else if (StatementAccountBillEnum.OTHERPARTY_CONFIRM.getStatus().equals(this.businessState)) {
        this.businessState = StatementAccountBillEnum.BOTH_CONFIRM.getStatus();
      }
    }
  }

  /**
   * 业务取消确认
   */
  public void businessCancelConfirmation() {
    if (!(this.generatedCollectionsPrice.compareTo(BigDecimal.ZERO) == 0)
            || !(this.generatedTicketPrice.compareTo(BigDecimal.ZERO) == 0)) {
      throw new BusinessException("该对账单已生成收付款单或已生成发票，取消失败！");
    }
    if (!this.state.equals(StatementAccountBillEnum.MONEY_UNRECEIVED.getStatus())
            || !this.ticketState.equals(StatementAccountBillEnum.NOT_INVOICE.getStatus())) {
      throw new BusinessException("该对账单已收款或已开发票，取消失败！");
    }
    //物流对账单区别对待
    if (this.customerType.equals(StatementAccountBillEnum.CUSTOMER_TYPE_LOGISTICS.getStatus())) {
      if (StatementAccountBillEnum.BOTH_CONFIRM.getStatus().equals(this.businessState)) {
        this.businessState = StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus();
      }
    } else {//上下游对账单
      if (StatementAccountBillEnum.OUR_CONFIRM.getStatus().equals(this.businessState)) {
        this.businessState = StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus();
      } else if (StatementAccountBillEnum.BOTH_CONFIRM.getStatus().equals(this.businessState)) {
        this.businessState = StatementAccountBillEnum.OTHERPARTY_CONFIRM.getStatus();
      }
    }
  }

  /**
   * 财务确认
   */
  public void financeConfirmation() {
    //物流对账单区别对待
    if (this.customerType.equals(StatementAccountBillEnum.CUSTOMER_TYPE_LOGISTICS.getStatus())) {
      if (StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus().equals(this.financeState)) {
        this.financeState = StatementAccountBillEnum.BOTH_CONFIRM.getStatus();
      }
    } else {//上下游对账单
      if (StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus().equals(this.financeState)) {
        this.financeState = StatementAccountBillEnum.OUR_CONFIRM.getStatus();
      } else if (StatementAccountBillEnum.OTHERPARTY_CONFIRM.getStatus().equals(this.financeState)) {
        this.financeState = StatementAccountBillEnum.BOTH_CONFIRM.getStatus();
      }
    }
  }

  /**
   * 财务取消确认
   */
  public void financeCancelConfirmation() {
    if (!(this.generatedCollectionsPrice.compareTo(BigDecimal.ZERO) == 0)
            || !(this.generatedTicketPrice.compareTo(BigDecimal.ZERO) == 0)) {
      throw new BusinessException("该对账单已生成收付款单或已生成发票，取消失败！");
    }
    if (!this.state.equals(StatementAccountBillEnum.MONEY_UNRECEIVED.getStatus())
            || !this.ticketState.equals(StatementAccountBillEnum.NOT_INVOICE.getStatus())) {
      throw new BusinessException("该对账单已收款或已开发票，取消失败！");
    }
    //物流对账单区别对待
    if (this.customerType.equals(StatementAccountBillEnum.CUSTOMER_TYPE_LOGISTICS.getStatus())) {
      if (StatementAccountBillEnum.BOTH_CONFIRM.getStatus().equals(this.financeState)) {
        this.financeState = StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus();
      }
    } else {//上下游对账单
      if (StatementAccountBillEnum.OUR_CONFIRM.getStatus().equals(this.financeState)) {
        this.financeState = StatementAccountBillEnum.BOTH_UNCONFIRM.getStatus();
      } else if (StatementAccountBillEnum.BOTH_CONFIRM.getStatus().equals(this.financeState)) {
        this.financeState = StatementAccountBillEnum.OTHERPARTY_CONFIRM.getStatus();
      }
    }
  }


  /**
   * 上传图片
   *
   * @param dto
   */
  public void uploadImages(FilesDto dto) {
    this.mainSrcImages = dto.getFiles();
  }

  /**
   * 对账单编号
   */
  private String code;
  /**
   * 收状态:0未收款, 1 部分收款 2 完成收款
   */
  private Short state;
  /**
   * 客户类型: 0上游, 1下游, 2物流
   */
  private Short customerType;
  /**
   * 往来单位id
   */
  private Long customerId;
  /**
   * 录单人id
   */
  private Long brokerageId;
  /**
   * 对账金额
   */
  private BigDecimal price;
  /**
   * 已收款金额
   */
  private BigDecimal makeCollectionsPrice;
  /**
   * 已生成收付款单金额
   */
  private BigDecimal generatedCollectionsPrice;
  /**
   * 生成日期
   */
  private Long inputTimestamp;
  /**
   * 业务确认状态:0双方都未确认,1只有服务商确认,2只有对方确认,3代表双方都确认
   */
  private Short businessState;
  /**
   * 财务确认状态:0双方都未确认,1只有服务商确认,2只有对方确认,3代表双方都确认
   */
  private Short financeState;
  /**
   * 开票状态:0未开票, 1 部分开票 2 完成开票
   */
  private Short ticketState;
  /**
   * 开票金额
   */
  private BigDecimal ticketPrice;
  /**
   * 已生成开票金额
   */
  private BigDecimal generatedTicketPrice;
  /**
   * 归属端id
   */
  private Long businessEntityId;
  /**
   * 单据图片
   */
  private String mainSrcImages;
  /**
   * 对账单项
   */
  private List<StatementAccountBillItem> statementAccountBillItems;
}
